1 /* 2 * Hunt - a framework for web and console application based on Collie using Dlang development 3 * 4 * Copyright (C) 2015-2017 Shanghai Putao Technology Co., Ltd 5 * 6 * Developer: HuntLabs 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.application.config; 13 14 import std.exception; 15 import std.parallelism : totalCPUs; 16 import std.socket : Address, parseAddress; 17 import kiss.logger; 18 import std.string; 19 20 import hunt.init; 21 import hunt.text.configuration; 22 import hunt.application.application : WebSocketFactory; 23 import hunt.application.application; 24 25 import collie.codec.http.server.httpserveroptions; 26 27 final class AppConfig 28 { 29 alias AddressList = Address[]; 30 31 struct ApplicationConf 32 { 33 string name = "HUNT APPLICATION"; 34 string baseUrl; 35 string defaultCookieDomain = ".example.com"; 36 string defaultLanguage = "zh-CN"; 37 string languages = "zh-CN,en-US"; 38 string secret = "CD6CABB1123C86EDAD9"; 39 string encoding = "utf-8"; 40 int staticFileCacheMinutes = 30; 41 } 42 43 struct SessionConf 44 { 45 string storage = "memory"; 46 string prefix = "huntsession_"; 47 string args = "/tmp"; 48 uint expire = 3600; 49 } 50 51 struct CacheConf 52 { 53 string storage = "memory"; 54 string args = "/tmp"; 55 bool enableL2 = false; 56 } 57 58 struct HttpConf 59 { 60 string address = "0.0.0.0"; 61 ushort port = 8080; 62 uint workerThreads = 4; 63 uint ioThreads = 2; 64 size_t keepAliveTimeOut = 30; 65 size_t maxHeaderSize = 60 * 1024; 66 int cacheControl; 67 string path; 68 } 69 70 struct HttpsConf 71 { 72 bool enabled = false; 73 string protocol; 74 string keyStore; 75 string keyStoreType; 76 string keyStorePassword; 77 } 78 79 struct RouteConf 80 { 81 string groups; 82 } 83 84 struct LogConfig 85 { 86 string level = "all"; 87 string path; 88 string file = ""; 89 bool disableConsole = false; 90 string maxSize = "8M"; 91 uint maxNum = 8; 92 } 93 94 struct MemcacheConf 95 { 96 bool enabled = false; 97 string servers; 98 } 99 100 struct RedisConf 101 { 102 bool enabled = false; 103 string host = "127.0.0.1"; 104 string password = ""; 105 ushort database = 0; 106 ushort port = 6379; 107 uint timeout = 0; 108 } 109 110 struct UploadConf 111 { 112 string path; 113 uint maxSize = 4 * 1024 * 1024; 114 } 115 116 struct MailSmtpConf 117 { 118 string host; 119 string channel; 120 ushort port; 121 string protocol; 122 string user; 123 string password; 124 } 125 126 struct MailConf 127 { 128 MailSmtpConf smtp; 129 } 130 131 struct DbPoolConf 132 { 133 uint maxConnection = 10; 134 uint minConnection = 10; 135 uint timeout = 10000; 136 } 137 138 struct DBConfig 139 { 140 string url; 141 DbPoolConf pool; 142 } 143 144 struct DateConf 145 { 146 string format; 147 string timeZone; 148 } 149 150 struct CornConf 151 { 152 string noon; 153 } 154 155 struct ServiceConf { 156 string address = "127.0.0.1"; 157 ushort port; 158 int workerThreads; 159 string password; 160 } 161 162 struct RpcConf { 163 bool enabled = true; 164 ServiceConf service; 165 } 166 167 struct Templates 168 { 169 string path; 170 } 171 172 DBConfig database; 173 ApplicationConf application; 174 SessionConf session; 175 CacheConf cache; 176 HttpConf http; 177 HttpsConf https; 178 RouteConf route; 179 MemcacheConf memcache; 180 RedisConf redis; 181 LogConfig log; 182 UploadConf upload; 183 CornConf cron; 184 DateConf date; 185 MailConf mail; 186 RpcConf rpc; 187 Templates templates; 188 189 @property Configuration config(){return _config;} 190 191 static AppConfig parseAppConfig(Configuration conf) 192 { 193 AppConfig app = new AppConfig(); 194 195 app._config = conf; 196 197 collectException(conf.application.name.value, app.application.name); 198 collectException(conf.application.baseUrl.value, app.application.baseUrl); 199 collectException(conf.application.defaultCookieDomain.value, app.application.defaultCookieDomain); 200 collectException(conf.application.defaultLanguage.value, app.application.defaultLanguage); 201 collectException(conf.application.languages.value, app.application.languages); 202 collectException(conf.application.secret.value, app.application.secret); 203 collectException(conf.application.encoding.value, app.application.encoding); 204 collectException(conf.application.staticFileCacheMinutes.as!int, app.application.staticFileCacheMinutes); 205 206 collectException(conf.session.storage.value(), app.session.storage); 207 collectException(conf.session.prefix.value(), app.session.prefix); 208 collectException(conf.session.args.value(), app.session.args); 209 collectException(conf.session.expire.as!uint(), app.session.expire); 210 211 collectException(conf.cache.storage.value(), app.cache.storage); 212 ///collectException(conf.cache.prefix.value(), app.cache.prefix); 213 collectException(conf.cache.args.value(), app.cache.args); 214 215 collectException(conf.http.address.value(), app.http.address); 216 collectException(conf.http.port.as!ushort(), app.http.port); 217 collectException(conf.http.workerThreads.as!uint(), app.http.workerThreads); 218 collectException(conf.http.ioThreads.as!uint(), app.http.ioThreads); 219 collectException(conf.http.maxHeaderSize.as!size_t(), app.http.maxHeaderSize); 220 collectException(conf.http.keepAliveTimeOut.as!size_t(), app.http.keepAliveTimeOut); 221 collectException(conf.http.cacheControl.as!int(), app.http.cacheControl); 222 collectException(conf.http.path.value(), app.http.path); 223 224 collectException(conf.https.enabled.as!bool(), app.https.enabled); 225 collectException(conf.https.protocol.value(), app.https.protocol); 226 collectException(conf.https.keyStore.value(), app.https.keyStore); 227 collectException(conf.https.keyStoreType.value(), app.https.keyStoreType); 228 229 collectException(conf.route.groups.value(), app.route.groups); 230 231 collectException(conf.memcache.enabled.as!bool(), app.memcache.enabled); 232 collectException(conf.memcache.servers.value(), app.memcache.servers); 233 234 collectException(conf.redis.enabled.as!bool(), app.redis.enabled); 235 collectException(conf.redis.host.value(), app.redis.host); 236 collectException(conf.redis.password.value(), app.redis.password); 237 collectException(conf.redis.database.as!ushort(), app.redis.database); 238 collectException(conf.redis.port.as!ushort(), app.redis.port); 239 collectException(conf.redis.timeout.as!uint(), app.redis.timeout); 240 241 collectException(conf.log.level.value(), app.log.level); 242 collectException(conf.log.path.value(), app.log.path); 243 collectException(conf.log.file.value(), app.log.file); 244 collectException(conf.log.disableConsole.as!bool(), app.log.disableConsole); 245 collectException(conf.log.maxSize.value(), app.log.maxSize); 246 collectException(conf.log.maxNum.as!uint(), app.log.maxNum); 247 248 collectException(conf.upload.path.value(), app.upload.path); 249 collectException(conf.upload.maxSize.as!uint(), app.upload.maxSize); 250 251 collectException(conf.cron.noon.value(), app.cron.noon); 252 253 collectException(conf.date.format.value(), app.date.format); 254 collectException(conf.date.timeZone.value(), app.date.timeZone); 255 256 collectException(conf.database.url.value(), app.database.url); 257 collectException(conf.database.pool.maxConnection.as!uint(), app.database.pool.maxConnection); 258 collectException(conf.database.pool.minConnection.as!uint(), app.database.pool.minConnection); 259 collectException(conf.database.pool.timeout.as!uint(), app.database.pool.timeout); 260 261 collectException(conf.mail.smtp.host.value(), app.mail.smtp.host); 262 collectException(conf.mail.smtp.channel.value(), app.mail.smtp.channel); 263 collectException(conf.mail.smtp.port.as!ushort(), app.mail.smtp.port); 264 collectException(conf.mail.smtp.protocol.value(), app.mail.smtp.protocol);. 265 collectException(conf.mail.smtp.user.value(), app.mail.smtp.user); 266 collectException(conf.mail.smtp.password.value(), app.mail.smtp.password); 267 268 collectException(conf.rpc.enabled.as!bool(), app.rpc.enabled); 269 collectException(conf.rpc.service.address.value(), app.rpc.service.address); 270 collectException(conf.rpc.service.port.as!ushort(), app.rpc.service.port); 271 collectException(conf.rpc.service.workerThreads.as!int(), app.rpc.service.workerThreads);. 272 collectException(conf.rpc.service.password.value(), app.rpc.service.password); 273 274 collectException(conf.templates.path.value(), app.templates.path); 275 276 return app; 277 } 278 279 private: 280 Configuration _config; 281 282 this() 283 { 284 http.workerThreads = totalCPUs; 285 } 286 } 287 288 import core.sync.rwmutex; 289 290 import std.file; 291 import std.path; 292 293 class ConfigNotFoundException : Exception 294 { 295 mixin basicExceptionCtors; 296 } 297 298 class ConfigManager 299 { 300 @property AppConfig app() 301 { 302 if(!_app) 303 { 304 setAppSection(""); 305 } 306 307 return _app; 308 } 309 310 @property string path() 311 { 312 return this._path; 313 } 314 315 void setConfigPath(string path) 316 { 317 if(path.empty) 318 return; 319 320 if(path[$-1] == '/') 321 this._path = path; 322 else 323 this._path = path ~ "/"; 324 } 325 326 void setAppSection(string sec, string fileName = "application.conf") 327 { 328 string fullName = buildPath(path, fileName); 329 if(exists(fullName)) 330 { 331 logDebugf("using config file: %s", fullName); 332 auto con = new Configuration(fullName, sec); 333 _app = AppConfig.parseAppConfig(con); 334 } 335 else 336 { 337 logDebug("using default configs."); 338 _app = new AppConfig(); 339 } 340 } 341 342 Configuration config(string key) 343 { 344 import std.format; 345 Configuration v = null; 346 synchronized(_mutex.reader) 347 { 348 v = _conf.get(key, null); 349 } 350 351 enforce!ConfigNotFoundException(v, format(" %s is not in config! ", key)); 352 353 return v; 354 } 355 356 void addConfig(string key, Configuration conf) 357 { 358 _mutex.writer.lock(); 359 scope(exit)_mutex.writer.unlock(); 360 _conf[key] = conf; 361 } 362 363 auto opDispatch(string s)() 364 { 365 return config(s); 366 } 367 368 private: 369 this() 370 { 371 _mutex = new ReadWriteMutex(); 372 _path = DEFAULT_CONFIG_PATH; 373 } 374 375 ~this(){_mutex.destroy;} 376 377 AppConfig _app; 378 379 Configuration[string] _conf; 380 381 string _path; 382 383 ReadWriteMutex _mutex; 384 } 385 386 @property ConfigManager Config() 387 { 388 return _manger; 389 } 390 391 shared static this() 392 { 393 _manger = new ConfigManager(); 394 } 395 396 private: 397 __gshared ConfigManager _manger;